//---HEADER
//	Todo: make String8 compatible with iostreams
//--------------------------------------------->
#include <RSLib/Common.hpp>
#ifndef RSLIB___STRING_HPP
#define RSLIB___STRING_HPP
 
 
 
//---INCLUDE
//----------------------->
#include <RSLib/Types.hpp>
#include <string> 
#include <stdio.h>//sprintf
 
 
 
namespace RSLib{
namespace String {
 
 
 
//---CLASS
//	Desc: thin wrapper around std::string
//	Note:	encapsulating std::string instead of deriving from has the advantage of being able to overload the char* cast operator
//			which would have not been possible because std::string overloads [].
//			this causes a clumsy syntax to invoke std::string methods but is solved by using functions to manipulate strings (such boost:string_algo)
//------------------------------------------------------------------------------------------------------------------------------------------------>
class String8
{
public:
	std::string string;
	
public:
	String8(){}
	String8(const std::string& string_) : string(string_){}
	String8(const char* string_) : string(string_){}
	String8(const char* string_, size_t chars) : string(string_,chars){}
	
public:
	operator const char*() const {return string.c_str();}
	operator char*() {return &string[0];}
	operator const std::string&() const {return string;}
	operator std::string&() {return string;}
	
public:
	template<typename T> String8(const T& value, const char* format)
	{
		size_t n = _scprintf(format,value);
		string.resize(n);
		sprintf(const_cast<char*>(string.c_str()),format,value);
	}
	String8(const Unsigned32& value)	: string( String8(value,"%u") ){}
	String8(const Integer32& value)	: string( String8(value,"%d") ){}
	String8(const Char8& value)		: string( String8(value,"%c") ){}	
	String8(const Float32& value)		: string( String8(value,"%f") ){}
	
public:
	String8 operator+(const String8& string_) const
	{
		return String8( string + string_.string );
	}
	bool operator==(const String8& string_) const
	{
		return (string.compare(string_.string) == 0);
	}
	bool operator==(const Char8* string_) const
	{
		return (string.compare(string_) == 0);
	}
	
public:
///PROPERTIES
	LargerUnsigned bytes() const	{return string.size()+1;}
	LargerUnsigned chars() const	{return string.size();}
	
	
public:
	template <typename T> static  T To(const Char8* string)				{return string;}
	template<> static Float32 To<Float32>(const Char8* string)			{return (Float32) atof(string); }
	template<> static Integer32 To<Integer32>(const Char8* string)		{return atoi(string); }
	template<> static Unsigned32 To<Unsigned32>(const Char8* string)	{return atoi(string); }
	template<> static Boolean To<Boolean>(const Char8* string)			{return (_strnicmp(string,"true",4)==0); }
};
 
 
//---FUNCTIONS
//	Desc:	free functions versions of std::string methods
//------------------------------------------------------------------------------------------->
inline LargerUnsigned Length(const std::string& string)					{return string.length();}
 
 
 
//---FUNCTION
//	Todo:	reimplement the boost lexical_cast
//			adding support for sprintf/sscanf format
//----------------------------------------------->
//template <typename Output, typename Input>
//inline Output lexical_cast(const Input& input)
//{
//	
//}
 
 
 
//---FILENAME MANIPULATION FUNCTIONS
//--------------------------------------->
//---FILENAME UTILITIES
//	Todo:	Move to File.hpp,File.cpp
//--------------------------------------------------------------->
#ifdef RSLIB___WINDOWS
#define RSLIB___DIRECTORY_SEPARATOR_CHAR '\\'
#endif
#ifdef RSLIB___LINUX
#define RSLIB___DIRECTORY_SEPARATOR_CHAR '/'
#endif
inline String8 FilePath(const Char8* filename, Boolean includeSlash = true)
{
	for(const Char8* p = filename + strlen(filename); p!=filename ;p--)
	{
		if (*p == RSLIB___DIRECTORY_SEPARATOR_CHAR) return String8( filename,p-filename + (includeSlash?1:0) );//return "Directory\Directory\"
	}
	return String8();
}
inline String8 FileWithoutPath(const Char8* filename)
{
	for(const Char8* p = filename + strlen(filename); p!=filename ;p--)
	{
		if (*p == RSLIB___DIRECTORY_SEPARATOR_CHAR) return String8(p+1);
	}
	return String8(filename);
}
inline String8 FileExtension(const Char8* filename)
{
	for(const Char8* p = filename + strlen(filename); p!=filename ;p--)
	{
		if (*p == RSLIB___DIRECTORY_SEPARATOR_CHAR) return String8();
		if (*p == '.') return String8(p+1);
	}
	return String8();
}
inline String8 FileName(const Char8* filename)
{
	const Char8* last = filename + strlen(filename);
	
	const Char8* p = last;
	const Char8* ext = last;
	for(; p!=filename ;p--)
	{
		if ((*p == '.') && (ext == last)) ext = p;
		if (*p == RSLIB___DIRECTORY_SEPARATOR_CHAR) return String8(p+1,ext-p-1);
	}
	return String8(p,ext-p);
}
#ifdef RSLIB___DIRECTORY_SEPARATOR_CHAR	//!TODO: replace with a #pragma macro push/pop
#undef RSLIB___DIRECTORY_SEPARATOR_CHAR
#endif
 
 
 
}//namespace String
 
 
 
using  String::String8;
 
 
 
}//namespace RSLib
 
 
 
#endif//RSLIB___STRING_HPP
